import logging
import copy
from datetime import datetime
from common.mg_core.mg import get_report_template, insert_or_update, get_report
from common.timeutil import get_interval_end_pair
from common.es_core.user_filter import UserFilter
from common.account import db as account_db
from common.es_core.report_creator import ReportCreator, UserReportCreator
from common.es_core.es_interface import es_search_interface
from event_rule.cp.product_event_rule.dwc_bet_user_analysis import DWC_BET_USER_ANALYSIS_CONFIG
from event_rule.cp.product_event_rule.lottery_bet_user_analysis import LOTTERY_BET_USER_ANALYSIS_CONFIG

_LOGGER = logging.getLogger(__name__)

LOTTERY_DCT = {
    'lottery_1': "重庆时时彩",
    'lottery_3': "江苏快三",
    'lottery_4': "山东11选5",
    'lottery_6': "天津时时彩",
    'lottery_7': "新疆时时彩",
    'lottery_8': "江西11选5",
    'lottery_9': "广东11选5",
    'lottery_10': "上海11选5",
    'lottery_11': "广西快3",
    'lottery_12': "北京PK10",
    'lottery_13': "重庆幸运农场",
    'lottery_15': "福彩3D",
    'lottery_17': "幸运分分彩",
    'lottery_18': "极速11选5",
    'lottery_19': "极速快3",
    'lottery_20': "极速PK10",
    'lottery_21': '幸运百家乐',
    'lottery_22': '幸运两面盘'
}

GAME_DCT = {
    '5500': "超级牛牛",
    '5501': "欢乐炸金花",
    '5502': "超级六",
    '5503': "龙虎斗",
    '5504': "金鲨银鲨",
    '5600': "放克猴子",
    'bull': '百人牛牛',
    'lottery': '大转盘',
    'fruit': '水果机',
}


def _get_aggregate_report_dynamic_argument_dct(index, start_time, end_time, target_event_id, custom_filter=None):
    # 赢家盈亏
    profit_user_filter = UserFilter(merchant_name=index)
    profit_user_filter.stage_filter(
        target_event_id, target_event_id + '_profit', 'sum', start_time, end_time, 0, custom_filter=custom_filter
    )
    profit_user_pool = profit_user_filter.get_user_pool()
    # 输家盈亏
    lose_user_filter = UserFilter(merchant_name=index)
    lose_user_filter.stage_filter(
        target_event_id, target_event_id + '_profit', 'sum', start_time, end_time, None, 0, custom_filter=custom_filter
    )
    lose_user_pool = lose_user_filter.get_user_pool()
    dynamic_target_users_dct = dict(
        profit_user_pool=profit_user_pool,
        lose_user_pool=lose_user_pool
    )
    return dynamic_target_users_dct


def lottery_aggregate_report_handler(interval_type, base_time, last_window, event_name, event_rule, index):
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window)
    collection = '_'.join(['game', event_name, 'report'])
    dynamic_argument_dct = _get_aggregate_report_dynamic_argument_dct(
        index, start_time, end_time, 'cp_lottery'
    )
    report_id = '-'.join(['all', str(start_time).split(' ')[0], interval_type.value])
    report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
    report_template.update(
        UserReportCreator.create_user_report(start_time=start_time, end_time=end_time, event_rule=event_rule,
                                             index=index, dynamic_argument_dct=dynamic_argument_dct)
    )
    report_template.update(dict(game_id='all', game_name='汇总'))
    insert_or_update(report_template, database=index, collection=collection)
    for lottery_id, lottery_name in LOTTERY_DCT.items():
        custom_filter = [{"term": {"cp_lottery_sub_type": int(lottery_id.split('_')[1])}}]
        dynamic_argument_dct = _get_aggregate_report_dynamic_argument_dct(
            index, start_time, end_time, 'cp_lottery', custom_filter=custom_filter
        )
        report_id = '-'.join([lottery_id, str(start_time).split(' ')[0], interval_type.value])
        report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
        report_template.update(dict(game_id=lottery_id, game_name=lottery_name))
        report_template.update(
            UserReportCreator.create_user_report(start_time=start_time, end_time=end_time,
                                                 event_rule=event_rule, index=index, custom_filter=custom_filter,
                                                 dynamic_argument_dct=dynamic_argument_dct)
        )
        insert_or_update(report_template, database=index, collection=collection)


def game_aggregate_report_handler(interval_type, base_time, last_window, event_name, event_rule, index):
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window)
    collection = '_'.join(['game', event_name, 'report'])
    dynamic_argument_dct = _get_aggregate_report_dynamic_argument_dct(
        index, start_time, end_time, 'cp_game'
    )
    report_id = '-'.join(['all', str(start_time).split(' ')[0], interval_type.value])
    report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
    report_template.update(
        UserReportCreator.create_user_report(start_time=start_time, end_time=end_time,
                                             event_rule=event_rule, index=index,
                                             dynamic_argument_dct=dynamic_argument_dct)
    )
    report_template.update(dict(game_id='all', game_name='汇总'))
    insert_or_update(report_template, database=index, collection=collection)
    for game_id, game_name in GAME_DCT.items():
        custom_filter = [{"term": {"cp_game_third_type": game_id}}]
        dynamic_argument_dct = _get_aggregate_report_dynamic_argument_dct(
            index, start_time, end_time, 'cp_game', custom_filter=custom_filter
        )
        report_id = '-'.join([game_id, str(start_time).split(' ')[0], interval_type.value])
        report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
        report_template.update(dict(game_id=game_id, game_name=game_name))
        report_template.update(
            UserReportCreator.create_user_report(start_time=start_time, end_time=end_time,
                                                 event_rule=event_rule, index=index, custom_filter=custom_filter,
                                                 dynamic_argument_dct=dynamic_argument_dct)
        )
        insert_or_update(report_template, database=index, collection=collection)


def _process_es_response(criteria, index):
    return es_search_interface(index, criteria)


def aggregate_data(interval_type, game_type, game_id, game_id_dct, index, base_time=None, last_window=False):
    _LOGGER.info('begin aggregate interval data, interval_type: [{}], base_time: [{}], last_window: [{}]'.format(
        interval_type.value, base_time, last_window))
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window)
    base_time = start_time
    aggregate_event_data(game_type, game_id, game_id_dct, base_time, start_time, end_time, index)
    _LOGGER.info('end aggregate interval data, interval_type: [{}], base_time: [{}], last_window: [{}]'.format(
        interval_type.value, base_time, last_window))


def _aggregate_game_term(game_type, game_id, start_time, end_time, index, result):
    aggs_dsl = {
        "query": {
            "bool": {
                "filter": [
                    {"term": {"_event_id": 'term_detail'}},
                    {"term": {"term_detail_sub_type": game_type}},
                    {"term": {"term_detail_third_type": game_id}},
                    {'range': {
                        "_event_time": {
                            "gte": start_time.timestamp(),
                            "lt": end_time.timestamp()
                        }
                    }}
                ]
            }
        },
        "size": 0,
        "aggs": {
            "bet_amount": {
                "sum": {
                    "field": "term_detail_bet_amount"
                }
            },
            "win_count": {
                "sum": {
                    "field": "term_detail_win_count"
                }
            },
            "award_amount": {
                "sum": {
                    "field": "term_detail_award_amount"
                }
            },
            "system_bet_amount": {
                "filter": {"term": {"term_detail_banker": 0}},
                "aggs": {
                    "_system_bet_amount": {"sum": {"field": "term_detail_bet_amount"}}
                }
            },
            "system_award_amount": {
                "filter": {"term": {"term_detail_banker": 0}},
                "aggs": {
                    "_system_award_amount": {"sum": {"field": "term_detail_award_amount"}}
                }
            },
            "system_origin_award": {
                "filter": {"term": {"term_detail_banker": 0}},
                "aggs": {
                    "_system_origin_award": {"sum": {"field": "term_detail_origin_award"}}
                }
            },
            "banker_tax": {
                "sum": {
                    "field": "term_detail_banker_tax"
                }
            },
            "banker_user": {
                "cardinality": {
                    "field": "term_detail_banker"
                }
            },
            "banker_count": {
                "filter": {'bool': {"must_not": {"term": {"term_detail_banker": 0}}}},
                "aggs": {
                    "_banker_count": {"value_count": {"field": "term_detail_banker"}}
                }
            },
            "banker_bet_amount": {
                "filter": {'bool': {"must_not": {"term": {"term_detail_banker": 0}}}},
                "aggs": {
                    "_banker_bet_amount": {"sum": {"field": "term_detail_bet_amount"}}
                }
            },
            "banker_award_amount": {
                "filter": {'bool': {"must_not": {"term": {"term_detail_banker": 0}}}},
                "aggs": {
                    "_banker_award_amount": {"sum": {"field": "term_detail_award_amount"}}
                }
            }
        }
    }
    es_response = _process_es_response(aggs_dsl, index)
    aggregations = es_response['aggregations']
    data = {
        'term_count': es_response['hits']['total'],
        'bet_amount': aggregations['bet_amount'].get('value', 0),
        'win_amount': aggregations['award_amount'].get('value', 0),
        'profit': aggregations['bet_amount'].get('value', 0) - aggregations['award_amount'].get('value', 0),
        'profit_rate': ((aggregations['bet_amount'].get('value', 0) - aggregations['award_amount'].get('value', 0)) /
                        (aggregations['bet_amount'].get('value', 0) + 1) * 100),
        'sys_banker_bet': aggregations['system_bet_amount'].get('_system_bet_amount', {}).get('value', 0),
        'sys_banker_award': aggregations['system_award_amount'].get('_system_award_amount', {}).get('value', 0),
        'sys_banker_origin_award': aggregations['system_origin_award'].get('_system_origin_award', {}).get('value', 0),
        'banker_person': aggregations['banker_user'].get('value', 0) - 1,
        'banker_count': aggregations['banker_count'].get('_banker_count', {}).get('value', 0),
        'banker_profit': ((aggregations['banker_bet_amount'].get('_banker_bet_amount', 0).get('value', 0) -
                           aggregations['banker_award_amount'].get('_banker_award_amount', 0).get('value', 0)) /
                          ((aggregations['banker_bet_amount'].get('_banker_bet_amount', 0)).get('value', 0) + 1) * 100)
    }
    data['sys_banker_profit'] = data['sys_banker_bet'] - data['sys_banker_award']
    data['sys_banker_origin_profit'] = data['sys_banker_bet'] - data['sys_banker_origin_award']
    data['sys_banker_profit_rate'] = data['sys_banker_profit'] / (data['sys_banker_bet'] + 1) * 100
    data['sys_banker_origin_profit_rate'] = data['sys_banker_origin_profit'] / (data['sys_banker_bet'] + 1) * 100
    result.update(data)


def _aggregate_game_user_data(game_type, game_id, start_time, end_time, index, result, user_pool=None):
    filter_list = [
        {"term": {"_event_id": 'cp_game'}},
        {'range': {
            "_event_time": {
                "gte": start_time.timestamp(),
                "lt": end_time.timestamp()
            }
        }}
    ]
    if game_type:
        filter_list.append({"term": {"cp_game_sub_type": game_type}})
    if game_id:
        filter_list.append({"term": {"cp_game_third_type": game_id}})
    if user_pool is not None:
        filter_list += [{"terms": {'_user_id': user_pool}}]
    aggs_dsl = {
        "query": {
            "bool": {
                "filter": filter_list
            }
        },
        "size": 0,
        "aggs": {
            "win_count": {
                "filter": {"range": {"cp_game_win": {"gt": 0}}},
                "aggs": {
                    "_win_count": {"value_count": {"field": "_user_id"}}
                }
            },
            "participate_user_count": {
                "cardinality": {"field": "_user_id"}
            },
            "group_win_user": {
                "terms": {
                    "field": "_user_id",
                    "size": 10000
                },
                "aggs": {
                    "total_bet": {
                        "sum": {
                            "field": "cp_game_price"
                        }
                    },
                    "total_award": {
                        "sum": {
                            "field": "cp_game_win"
                        }
                    },
                    "win_user_filter": {
                        "bucket_selector": {
                            "buckets_path": {
                                "total_award": "total_award",
                                "total_bet": "total_bet"
                            },
                            "script": "params.total_award > params.total_bet"
                        }
                    }
                }
            },
            "total_win_user_bet": {
                "sum_bucket": {
                    "buckets_path": "group_win_user>total_bet"
                }
            },
            "total_win_user_award": {
                "sum_bucket": {
                    "buckets_path": "group_win_user>total_award"
                }
            },
            "group_lose_user": {
                "terms": {
                    "field": "_user_id",
                    "size": 10000
                },
                "aggs": {
                    "total_bet": {
                        "sum": {
                            "field": "cp_game_price"
                        }
                    },
                    "total_award": {
                        "sum": {
                            "field": "cp_game_win"
                        }
                    },
                    "lose_user_filter": {
                        "bucket_selector": {
                            "buckets_path": {
                                "total_award": "total_award",
                                "total_bet": "total_bet"
                            },
                            "script": "params.total_award < params.total_bet"
                        }
                    }
                }
            },
            "total_lose_user_bet": {
                "sum_bucket": {
                    "buckets_path": "group_lose_user>total_bet"
                }
            },
            "total_lose_user_award": {
                "sum_bucket": {
                    "buckets_path": "group_lose_user>total_award"
                }
            }
        }
    }
    es_response = _process_es_response(aggs_dsl, index)
    aggregations = es_response['aggregations']
    result['participate_user'] = aggregations['participate_user_count'].get('value', 0)
    result['win_count'] = aggregations['win_count']['_win_count'].get('value', 0)
    result['win_user_count'] = len(aggregations['group_win_user']['buckets'])
    result['win_user_amount'] = aggregations['total_win_user_bet'].get('value')
    result['win_user_profit'] = (aggregations['total_win_user_award'].get('value', 0) -
                                 aggregations['total_win_user_bet'].get('value', 0))
    result['lose_user_count'] = len(aggregations['group_lose_user']['buckets'])
    result['lose_user_amount'] = aggregations['total_lose_user_bet'].get('value')
    result['lose_user_profit'] = (aggregations['total_lose_user_award'].get('value', 0) -
                                  aggregations['total_lose_user_bet'].get('value', 0))


def _aggregate_game_graph_data(game_type, game_id, game_id_dct, start_time, end_time, index, result):
    aggs_dsl = {
        "query": {
            "bool": {
                "filter": [
                    {"term": {"_event_id": "cp_game"}},
                    {"term": {"cp_game_sub_type": game_type}},
                    {"term": {"cp_game_third_type": game_id}},
                    {'range': {
                        "_event_time": {
                            "gte": start_time.timestamp(),
                            "lt": end_time.timestamp()
                        }
                    }}
                ]
            }
        },
        "size": 0,
        "aggs": {
            "buckets_count": {
                "cardinality": {
                    "field": "cp_game_bet_target.keyword"
                }
            },
            "bet_report": {
                "terms": {"field": "cp_game_bet_target.keyword"},
                "aggs": {
                    "bet_count": {
                        "value_count": {"field": "cp_game_out_trans_id"}
                    },
                    "bet_price": {
                        "sum": {"field": "cp_game_price"}
                    }
                }
            },
            "group_bet_target_slots": {
                "range": {
                    "field": "cp_game_price",
                    "ranges": [
                        {"to": 1.0},
                        {"from": 1.0, "to": 10.0},
                        {"from": 10.0, "to": 100.0},
                        {"from": 100}
                    ]
                },
                "aggs": {
                    "bet_count": {
                        "value_count": {"field": "cp_game_out_trans_id"}
                    },
                }
            }
        }
    }
    es_response = _process_es_response(aggs_dsl, index)
    aggregations = es_response['aggregations']
    bet_report_buckets = aggregations['bet_report']['buckets']
    slots_report_buckets = aggregations['group_bet_target_slots']['buckets']
    bet_target = game_id_dct.get('bet_target', {})
    index_result = {
        'term_detail_bet_region_index': [],
        'term_detail_bet_region_count_index': [],
        'term_detail_bet_amount_slot_index': [],
        'term_detail_win_region_index': []
    }
    for bucket in bet_report_buckets:
        index_result['term_detail_bet_region_count_index'].append({
            'key': bet_target.get(str(bucket['key']), '未知'),
            'value': bucket['bet_count'].get('value', 0)
        })
        index_result['term_detail_bet_region_index'].append({
            'key': bet_target.get(str(bucket['key']), '未知'),
            'value': bucket['bet_price'].get('value', 0)
        })
    for bucket in slots_report_buckets:
        index_result['term_detail_bet_amount_slot_index'].append({
            'key': bucket['key'],
            'value': bucket['bet_count'].get('value')
        })
    aggs_dsl = {
        "query": {
            "bool": {
                "filter": [
                    {"term": {"_event_id": "term_detail"}},
                    {"term": {"term_detail_sub_type": game_type}},
                    {"term": {"term_detail_third_type": game_id}},
                    {'range': {
                        "_event_time": {
                            "gte": start_time.timestamp(),
                            "lt": end_time.timestamp()
                        }
                    }}
                ]
            }
        },
        "size": 0,
        "aggs": {
            "win_region": {
                "terms": {"field": "term_detail_win_index.keyword"},
                "aggs": {
                    "win_count": {
                        "value_count": {"field": "term_detail_bet_count"}
                    }
                }
            },
        }
    }
    es_response = _process_es_response(aggs_dsl, index)
    win_region_buckets = es_response['aggregations']['win_region']['buckets']
    win_index = {}
    for bucket in win_region_buckets:
        try:
            bucket['key'] = int(bucket['key'])
        except:
            pass
        key = bet_target.get(str(bucket['key']), '未知')
        print(str(bucket['key']))
        win_index_count = bucket['win_count'].get('value')
        if key not in bet_target and str(bucket['key']) in game_id_dct.get('win_index_mapper', {}):
            for _key in game_id_dct.get('win_index_mapper', {}).get(str(bucket['key'])):
                win_index_count = bucket['win_count'].get('value')
                win_index[_key] = win_index[_key] + win_index_count if _key in win_index else win_index_count
        else:
            win_index[key] = win_index[key] + win_index_count if key in win_index else win_index_count
    print(win_index)
    index_result['term_detail_win_region_index'] = [{'key': key, 'value': value} for key, value in win_index.items()]
    result.update(index_result)


def aggregate_event_data(game_type, game_id, game_id_dct, base_time, start_time, end_time, index):
    result = dict({
        '_id': '-'.join([str(game_type), str(game_id), str(base_time).split(' ')[0]]),
        'day': str(base_time).split(' ')[0],
        'base_time': base_time,
        'game_type': game_type,
        'game_id': game_id,
    })
    print(index)
    _aggregate_game_term(game_type, game_id, start_time, end_time, index, result)
    _aggregate_game_user_data(game_type, game_id, start_time, end_time, index, result)
    _aggregate_game_graph_data(game_type, game_id, game_id_dct, start_time, end_time, index, result)
    insert_or_update(result, database=index, collection='term_report')


def get_game_aggregate_analysis_preset():
    preset = [{'key': 'lottery', 'name': '彩票', 'third_type': []}, {'key': 'dwc', 'name': '电玩城', 'third_type': []}]
    for key, value in LOTTERY_DCT.items():
        preset[0]['third_type'].append({"key": key, "name": value})
    for key, value in GAME_DCT.items():
        preset[1]['third_type'].append({"key": key, "name": value})
    return preset


def bet_user_analysis_report_handler(interval_type, base_time, last_window, event_name, event_rule, index):
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window)
    base_user_pool = None
    game_type = 'dwc' if event_name == "dwc_bet_user_analysis" else 'lottery'
    report_id = '-'.join(['all', str(start_time).split(' ')[0], interval_type.value])
    report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
    report_template.update(dict(game_id=game_type, game_name='汇总', room_id='all', room_name='汇总'))
    _create_user_analysis_report(index, start_time, end_time, event_name, base_user_pool=base_user_pool,
                                 event_rule=event_rule, base_report_template=report_template)

    dct = GAME_DCT if event_name == "dwc_bet_user_analysis" else LOTTERY_DCT
    for game_id, game_name in dct.items():
        custom_filter = [{"term": {"cp_game_third_type": game_id}}] if event_name == "dwc_bet_user_analysis" else [
            {"term": {"cp_lottery_sub_type": int(game_id.split('_')[1])}}]
        report_id = '-'.join([game_id, str(start_time).split(' ')[0], interval_type.value])
        report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
        report_template.update(dict(game_id=game_type, game_name='', room_id=game_id, room_name=game_name))
        _create_user_analysis_report(index, start_time, end_time, event_name, base_user_pool=base_user_pool,
                                     base_custom_filter=custom_filter, event_rule=event_rule,
                                     base_report_template=report_template)


def _create_user_analysis_report(index, start_time, end_time, event_name, base_custom_filter=None, base_user_pool=None,
                                 event_rule=None, base_report_template=None):
    collection = '_'.join(['game', event_name, 'report'])
    user_analysis_report = ReportCreator.create_report(user_pool=base_user_pool, start_time=start_time,
                                                       end_time=end_time, event_rule=event_rule, index=index,
                                                       custom_filter=base_custom_filter, to_group=True,
                                                       max_bucket=20000)
    user_id_list = [user_report['_user_id'] for user_report in user_analysis_report['list']]
    users, _ = account_db.list_user(index, {'user_id__in': user_id_list}, disable_paginate=True)
    user_dct = {str(user['user_id']): user for user in users}
    for user_report in user_analysis_report['list']:
        report_template = copy.deepcopy(base_report_template)
        report_template['_id'] = '-'.join([report_template['_id'], str(user_report['_user_id'])])
        user = user_dct.get(str(user_report['_user_id']), {})
        user_report['chn'] = user.get('channel', '未知')
        user_report['registered_at'] = str(user.get('registered_at', '未知'))
        report_template.update(user_report)
        insert_or_update(report_template, database=index, collection=collection)


def get_user_analysis_report(index, amount_max=None, amount_min=None, user_id=None, chn_filter_list=None,
                             time_range=None, registered_time_range=None, game_id=None, game_id_list=None,
                             disable_paginate=None, sort_by=None, page=None, size=None):
    result_condition = dict()
    if amount_max is not None and amount_min is not None:
        assert amount_min <= amount_max
        if amount_max == amount_min:
            result_condition['bet_amount'] = amount_max
        else:
            result_condition['bet_amount'] = {'$gte': amount_min, '$lte': amount_max}
    elif amount_max is not None and amount_min is None:
        result_condition['bet_amount'] = {'$lte': amount_max}
    elif amount_max is None and amount_min is not None:
        result_condition['bet_amount'] = {'$gte': amount_min}
    condition = dict()
    if user_id:
        condition['_user_id'] = {'$in': user_id}
    if chn_filter_list:
        condition['chn'] = {'$in': chn_filter_list}
    if game_id_list:
        condition['room_id'] = {'$in': game_id_list}
    condition['day'] = {'$gte': datetime.strftime(time_range[0], "%Y-%m-%d"),
                        '$lte': datetime.strftime(time_range[1], "%Y-%m-%d")}
    condition['registered_at'] = {'$gte': datetime.strftime(registered_time_range[0], '%Y-%m-%d %H:%M:%S'),
                                  '$lte': datetime.strftime(registered_time_range[1], '%Y-%m-%d %H:%M:%S')}
    (collection, event_rule) = ('game_dwc_bet_user_analysis_report', DWC_BET_USER_ANALYSIS_CONFIG) if game_id == 'dwc' \
        else ('game_lottery_bet_user_analysis_report', LOTTERY_BET_USER_ANALYSIS_CONFIG)

    custom_group_by_field = {
        'registered_at': {"$first": '$registered_at'},
        'chn': {"$first": "$chn"},
        '_user_id': {"$first": "$_user_id"},
        'room_name': {"$first": "$room_name"}
    }
    group_key = '_user_id'
    if len(game_id_list) > 1:
        group_key = {'_user_id': '$_user_id', 'room_name': '$room_name'}
    analysis_result, total_count = get_report(index, collection, condition, sort_key=sort_by, page=page, size=size,
                                              disable_paginate=disable_paginate, merge_report=True,
                                              event_rule=event_rule, group_key=group_key,
                                              custom_group_by_field=custom_group_by_field,
                                              result_condition=result_condition)
    return analysis_result, total_count
